﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;
using System.Collections;

namespace popLib.CustomeControl
{
    public partial class EFDataMgrPanel : UserControl
    {
        public ObjectContext Entity { get; set; }
        public dynamic ObjectDataSet { get; set; }
        public List<SearchItem> SearchList { get; set; }
        private bool _updateMode;
        public bool UpdateMode
        {
            get { return _updateMode; }
            set
            {
                _updateMode = value;                
                dgv_data.AllowUserToAddRows = UpdateMode;
                dgv_data.AllowUserToDeleteRows = UpdateMode;
                btn_cancel.Enabled = btn_reset.Enabled = btn_save.Enabled = _updateMode;
                btn_update.Enabled = btn_search.Enabled = !_updateMode;
                if (UpdateModeChanged != null) UpdateModeChanged(this, value);
                if (ShowContextMenu) dgv_data.ContextMenuStrip = contextMenuStrip1;
            }
        }
        private bool _AllowAutoCompleteComboBox = true;
        public bool AllowAutoCompleteComboBox { 
            get 
            { 
                return _AllowAutoCompleteComboBox; 
            } 
            set 
            { 
                _AllowAutoCompleteComboBox = value;
            } 
        }
        public int ItemPerPage { get; set; }
        public string OrderByField { get; set; }
        public bool ShowContextMenu { get; set; }

        public delegate void UpdateModeChangedEvent(EFDataMgrPanel control, bool updateMode);
        public event UpdateModeChangedEvent UpdateModeChanged;

        public delegate void DataSavedEvent(EFDataMgrPanel control);
        public event DataSavedEvent DataSaved;
        public event DataSavedEvent DataSaving;
        public delegate void SaveErrorEvent(Exception ex, string defaulMessage);
        public event SaveErrorEvent SaveError;

        public Button SearchButton { get { return btn_search; } }
        public DataGridView DataGridViewControl { get { return dgv_data; } }

        private FormLanguage _Language;
        public FormLanguage Language
        {
            get { return _Language; }
            set
            {
                _Language = value;
                pageBar1.Language = value;

                switch (_Language)
                {
                    case FormLanguage.Vietnamese:
                        btn_cancel.Text = "Hủy";
                        btn_reset.Text = "Làm lại";
                        btn_save.Text = "Lưu";
                        btn_search.Text = "Tìm kiếm";
                        btn_update.Text = "Cập nhật";
                        clearContentToolStripMenuItem.Text = "Xóa nội dung";
                        break;
                    case FormLanguage.English:
                    case FormLanguage.Custom:
                    default:
                        btn_cancel.Text = "Cancel";
                        btn_reset.Text = "Reset";
                        btn_save.Text = "Save";
                        btn_search.Text = "Search";
                        btn_update.Text = "Update";
                        clearContentToolStripMenuItem.Text = "Clear cell content";
                        break;
                }
            }
        }

        public EFDataMgrPanel()
        {
            InitializeComponent();
        }

        public EFDataMgrPanel(ObjectContext entity, dynamic dataset, int itemPerPage, string orderByField, List<SearchItem> searchList)
        {
            InitializeComponent();
            InitForm(entity, dataset, searchList, itemPerPage, orderByField);
        }

        public void InitForm(ObjectContext entity, dynamic dataset, int itemPerPage, string orderByField, List<SearchItem> searchList)
        {
            InitForm(entity, dataset, searchList, itemPerPage, orderByField);
        }

        public void InitForm(ObjectContext entity, dynamic dataset, List<SearchItem> searchList, int itemPerPage, string orderByField)
        {
            Entity = entity;
            ObjectDataSet = dataset;
            SearchList = searchList;

            ItemPerPage = itemPerPage;
            OrderByField = orderByField;

            foreach (var item in SearchList)
            {
                if (item.IsSearchField) flp_searchContainer.Controls.Add(item.BuildSearchControl());                
                dgv_data.Columns.Add(item.FieldColumn);
            }

            dgv_data.AutoGenerateColumns = false;

            //update lai groupbox search
            if (searchList.Where(x => x.IsSearchField).Count() > 0)
            {
                gbx_search.Height = searchList.Where(x => x.IsSearchField).Last().Location.Y + 90;
                dgv_data.Location = new Point(dgv_data.Location.X, gbx_search.Location.Y + gbx_search.Height + 10);
                dgv_data.Height = this.Height - dgv_data.Location.Y - 40;
            }

            UpdateMode = false;

            Search(1);

            foreach (var item in SearchList)
            {
                if (item.IsSearchField)
                {
                    if (item.DataControl.GetType().Name == "ComboBox")
                    {
                        ((ComboBox)item.DataControl).SelectedIndex = -1;
                        item.DataControl.KeyDown += new KeyEventHandler(DataControl_KeyDown);
                    }

                    if (item.DataControl.GetType().Name == "TextBox")
                    {
                        item.DataControl.Text = "";
                        item.DataControl.KeyDown += new KeyEventHandler(DataControl_KeyDown);
                    }
                }
            }

            Search(1);

        }

        void DataControl_KeyDown(object sender, KeyEventArgs e)
        {
            if( e.KeyCode == Keys.Enter )
                btn_search.PerformClick();
        }
                
        private void btn_search_Click(object sender, EventArgs e)
        {
            Search(1);
        }

        public void Search( int page )
        {
            FormLib.showAnimatedLoading(this, "Loading...", true);

            var rs = ObjectDataSet;
            string searchQuery = "";
            List<ObjectParameter> parameters = new List<ObjectParameter>();
            int counter = 0;

            foreach (var item in SearchList)
            {
                if (!item.IsSearchField) continue;                
                switch (item.DataControl.GetType().Name)
                {
                    default:
                    case "TextBox":
                        if (item.DataControl.Text.isValid() && (ObjectDataSet.EntitySet.ElementType.Properties[item.FieldName].TypeUsage.ToString().Contains(".String") || item.IsTextSearch))
                        {
                            //neu co searchkeyword thi thay dzo, otherwise lay chinh field name
                            searchQuery += string.Format("it.{0} LIKE @{1} AND ", item.SearchKeyWord.isValid() ? item.SearchKeyWord : item.FieldName , item.FieldName + counter);
                            parameters.Add(new ObjectParameter(item.FieldName + counter, "%" + item.DataControl.Text + "%"));
                        }
                        else if (item.DataControl.Text.isValid())
                        {
                            searchQuery += string.Format("it.{0} == @{1} AND ", item.FieldName, item.FieldName + counter);

                            if (ObjectDataSet.EntitySet.ElementType.Properties[item.FieldName].TypeUsage.ToString().Contains(".Int"))
                                parameters.Add(new ObjectParameter(item.FieldName + counter, NumberLib.getInt(item.DataControl.Text)));
                            else
                                parameters.Add(new ObjectParameter(item.FieldName + counter, NumberLib.getDouble(item.DataControl.Text)));
                        }
                        break;
                    case "CheckBox":
                        if (((CheckBox)item.DataControl).CheckState != CheckState.Indeterminate )
                        {
                            searchQuery += string.Format("it.{0} == @{1} AND ", item.FieldName, item.FieldName + counter);
                            parameters.Add(new ObjectParameter(item.FieldName + counter, ((CheckBox)item.DataControl).Checked));
                        }
                        break;
                    case "ComboBox":
                        if (((ComboBox)item.DataControl).SelectedIndex != -1 && ((ComboBox)item.DataControl).SelectedValue != null)
                        {
                            searchQuery += string.Format("it.{0} == @{1} AND ", item.FieldName, item.FieldName + counter);
                            parameters.Add(new ObjectParameter(item.FieldName + counter, ((ComboBox)item.DataControl).SelectedValue));
                        }
                        break;
                    case "DateTimePicker":
                        if (((DateTimePicker)item.DataControl).Checked)
                        {
                            searchQuery += string.Format("it.{0} == @{1} AND ", item.FieldName, item.FieldName + counter);
                            parameters.Add(new ObjectParameter(item.FieldName + counter, ((DateTimePicker)item.DataControl).Value));
                        }
                        break;
                }

                counter++;
            }

            if (searchQuery.isValid())
            {
                searchQuery = (searchQuery + "@").Replace(" AND @", "");
                rs = ObjectDataSet.Where(searchQuery, parameters.ToArray());
            }

            var rss = ((IQueryable<dynamic>)rs).OrderByField(OrderByField,false);

            ReturnSet result = DataLib.ProcessPageData(page, (IQueryable<dynamic>)rss, ItemPerPage == 0 ? 100 : ItemPerPage);

            if (result.Success)
            {
                PageData pageData = (PageData)result.Result;
                pageBar1.PageSource = pageData;

                dgv_data.DataSource = pageBar1.PageSource.DataSource;
            }

            FormLib.hideLoading(this);
        }

        
        private void btn_save_Click(object sender, EventArgs e)
        {
            try
            {
                if (DataSaving != null) DataSaving(this);

                Entity.SaveChanges(SaveOptions.AcceptAllChangesAfterSave);

                UpdateMode = false;

                if (DataSaved != null) DataSaved(this);
            }
            catch (Exception ex)
            {
                string message = "Cannot save object!!!\r\nException:"+ex.Message + (ex.InnerException != null ? "\r\nInner Exception:" + ex.InnerException.Message : "");
                if (Language == FormLanguage.Vietnamese)
                    message = "Không thể lưu dữ liệu!!!\r\nException:" + ex.Message + (ex.InnerException != null ? "\r\nInner Exception:" + ex.InnerException.Message : "");
                if (SaveError != null)
                {
                    SaveError(ex, message);
                }
                else
                {
                    FormLib.alert(message);
                }
            }
        }

        private void btn_reset_Click(object sender, EventArgs e)
        {
            Entity.RollBack();
        }

        private void dgv_data_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            e.Cancel = true;
        }

        private void btn_update_Click(object sender, EventArgs e)
        {
            UpdateMode = true;          
        }

        private void btn_cancel_Click(object sender, EventArgs e)
        {
            Entity.RollBack();
            UpdateMode = false;
        }

        private void dgv_data_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        {
            if (!UpdateMode)
                e.Cancel = true;
        }

        private void dgv_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {
            if (!AllowAutoCompleteComboBox) return;
            if (e.Control is DataGridViewComboBoxEditingControl)
            {
                ((ComboBox)e.Control).DropDownStyle = ComboBoxStyle.DropDown;
                ((ComboBox)e.Control).AutoCompleteSource = AutoCompleteSource.ListItems;
                ((ComboBox)e.Control).AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend;
            }
        }

        private void dgv_data_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            if( dgv_data.Columns[dgv_data.CurrentCell.ColumnIndex].GetType().Name == "DataGridViewComboBoxColumn")
                dgv_data.CommitEdit(DataGridViewDataErrorContexts.Commit);
        }

        private void pageBar1_PageChanged(int page)
        {
            Search(page);
        }

        private void clearContentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if( UpdateMode )
                dgv_data.CurrentCell.Value = null;
        }
    }

    public class SearchItem : FlowLayoutPanel
    {
        public Label TitleControl { get; set; }
        public Control DataControl { get; set; }
        public string FieldName { get; set; }
        public bool IsSearchField { get; set; }
        public bool IsTextSearch { get; set; }
        public bool IsShowTitleControl { get; set; }
        public string SearchKeyWord { get; set; }//dung de search cac field ko co trong bang chinh vd user.userid = employee.user_id -> search username trong employee -> value is user.username

        public DataGridViewColumn FieldColumn { get; set; }

        public SearchItem(DataGridViewColumn column, bool isSearchField = true, bool isShowTitleControl = true)
        {
            this.AutoSize = true;
            this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
            this.IsSearchField = isSearchField;
            this.IsShowTitleControl = isShowTitleControl;
            this.Margin = new System.Windows.Forms.Padding(3, 0,3,0);
            this.Padding = new System.Windows.Forms.Padding(0);

            FieldColumn = column;
            FieldName = FieldColumn.DataPropertyName;            
        }

        public SearchItem SetSearchText(string searchKeyWord = null)
        {
            IsTextSearch = true;
            SearchKeyWord = searchKeyWord;
            return this;
        }

        public SearchItem BuildSearchControl()
        {
            //init label
            TitleControl = new Label();
            TitleControl.Text = FieldColumn.HeaderText;
            TitleControl.Size = new Size(120, 23);
            TitleControl.Margin = new Padding(10,3,3,3);
            TitleControl.TextAlign = ContentAlignment.MiddleRight;
            if (IsShowTitleControl) this.Controls.Add(TitleControl);

            switch ( IsTextSearch ? "DataGridViewTextBoxColumn" : FieldColumn.GetType().Name)
            {
                case "DataGridViewCheckBoxColumn": 
                    DataControl = new CheckBox();
                    ((CheckBox)DataControl).ThreeState = true;
                    ((CheckBox)DataControl).CheckState = CheckState.Indeterminate;
                    DataControl.Text = FieldColumn.HeaderText;
                    TitleControl.Text = "";
                    this.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
                    if (!IsShowTitleControl)
                    {
                        ((CheckBox)DataControl).AutoSize = true;
                    }
                    break;
                case "DataGridViewComboBoxColumn":
                    DataControl = new ComboBox();
                    ((ComboBox)DataControl).DisplayMember = ((DataGridViewComboBoxColumn)FieldColumn).DisplayMember;
                    ((ComboBox)DataControl).ValueMember = ((DataGridViewComboBoxColumn)FieldColumn).ValueMember;
                    ((ComboBox)DataControl).DataSource = ((DataGridViewComboBoxColumn)FieldColumn).DataSource;
                    ((ComboBox)DataControl).SelectedIndex = -1;
                    break;
                                
                case "CalendarColumn":
                    DataControl = new DateTimePicker();
                    ((DateTimePicker)DataControl).Format = DateTimePickerFormat.Custom;
                    ((DateTimePicker)DataControl).CustomFormat = FieldColumn.DefaultCellStyle.Format;
                    ((DateTimePicker)DataControl).ShowCheckBox = true;
                    ((DateTimePicker)DataControl).Checked = false;
                    break;
                default:
                case "DataGridViewTextBoxColumn": 
                case "DataGridViewImageColumn":
                case "DataGridViewLinkColumn": 
                case "DataGridViewButtonColumn": 
                    DataControl = new TextBox();
                break;
            }

            DataControl.Size = new Size(200, DataControl.Height);

            

            this.Controls.Add(DataControl);
            return this;
        }

        public void ReloadCoboBoxDataSource(object datasource, string displayMember, string valueMember)
        {
            if (FieldColumn == null) return;
            if (FieldColumn.GetType().Name != "DataGridViewComboBoxColumn") return;
            FieldColumn.SetComboBoxDataSource(datasource, displayMember, valueMember);
            if (!IsSearchField) return;
            if ( DataControl.GetType().Name != "ComboBox" ) return;
            ((ComboBox)DataControl).DataSource = datasource;
            ((ComboBox)DataControl).DisplayMember = displayMember;
            ((ComboBox)DataControl).ValueMember = valueMember;
        }
    }
}
